其他
java序列化与反序列化
本文为看雪论坛优秀文章
看雪论坛作者ID:p1yang
序列化与反序列化
一
基础知识
则一个字最大为 FFFF。
一个doubleword为FFFF FFFF。
比如0x12345678就需要四个字节。
我们称这两种为 小端序和大端序。
大端序
各家架构不同,使用的大小端序不同,无需纠结。
二
序列化与反序列化
三
实现java序列化和反序列化
JDK类库中序列化和反序列化API
表示对象输出流;
它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中;
表示对象输入流;它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回;
实现序列化的要求
实现Java对象序列化与反序列化的方法
ObjectOutputStream采用默认的序列化方式,对User对象的非transient的实例变量进行序列化。
ObjcetInputStream采用默认的反序列化方式,对对User对象的非transient的实例变量进行反序列化。
ObjectOutputStream调用User对象的writeObject(ObjectOutputStream out)的方法进行序列化。
ObjectInputStream会调用User对象的readObject(ObjectInputStream in)的方法进行反序列化。
ObjectOutputStream调用User对象的writeExternal(ObjectOutput out))的方法进行序列化。
ObjectInputStream会调用User对象的readExternal(ObjectInput in)的方法进行反序列化。
实例
import java.io.Serializable;
public class User implements Serializable {
int id;
String name;
String phone;
#一些get set 构造参数,这里就不列举了
}
import java.io.*;
public class userDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建对象
User u1 = new User(1,"AAAAAAA","110"); //被序列化的对象
User u2; //反序列化的对象
//序列化
getSerial(u1);
//反序列化
u2 = backSerial();
System.out.println(u2.getName());
}
//序列化
static void getSerial(User u1) throws IOException {
FileOutputStream fos = new FileOutputStream("obj.out");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(u1);
oos.flush();
oos.close();
}
//反序列化
static User backSerial() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("obj.out");
ObjectInputStream ois = new ObjectInputStream(fis);
User u1 = (User) ois.readObject();
return u1;
}
}
四
序列化底层分析
bout是数据输出流的底层
writeStreamHeader将文件头写入文件
writeObject(u1);
写入序列化uid
out.writeByte(flags);
然后调用writeShort写入两个字节的域长度(比如说有3个变量,就写入 00 03 )。
黄色 phone 参数 string
这里第一次看有个疑问,phone参数也是string,但是他却没Ljava/lang/string;这一串,后边又增加一个string的参数,确定同一种引用数据类型只写入一次。
bout.writeByte(TC_ENDBLOCKDATA);
循环结束,直到所有运行完成,回到主函数。
反序列化就不写了,反反过来推一遍就成。
五
java反射机制
import java.lang.reflect.Method;
public class test {
public static void main(String[] args) throws Exception {
a1Class a1 = new a1Class();
//通过运行时的对象调用getClass();
Class c = a1.getClass();
try {
//getMethod(方法名,参数类型)
//getMethod第一个参数是方法名,第二个参数是该方法的参数类型
//因为存在同方法名不同参数这种情况,所以只有同时指定方法名和参数类型才能唯一确定一个方法
Method m1 = c.getMethod("print", int.class, int.class);
//相当于r1.print(1, 2);方法的反射操作是用m1对象来进行方法调用 和r1.print调用的效果完全相同
//使用r1调用m1获得的对象所声明的公开方法即print,并将int类型的1,2作为参数传入
Object i = m1.invoke(a1,1,1);
}catch (Exception e){
e.printStackTrace();
}
}
static class a1Class {
public void print(int a, int b) {
System.out.println(a + b);
}
}
}
尝试简化上面的代码
public class testMiao {
public static void maio(){
System.out.println("miao!");
}
}
public class test {
public static void main(String[] args) throws Exception {
try {
Object s = Class.forName("testMiao").getMethod("maio").invoke(null);
}catch (Exception e){
e.printStackTrace();
}
}
}
尝试添加参数简化
public class testMiao {
public static void maio(String s){
System.out.println("miao!"+s);
}
}
public class test {
public static void main(String[] args) throws Exception {
try {
Class.forName("testMiao").getMethod("maio", String.class).invoke(Class.forName("testMiao"),"aaa");
}catch (Exception e){
e.printStackTrace();
}
}
}
六
java执行命令
如:
Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke("open /System/Applications/Calculator.app\n");
说明exec只能是通过getRuntime来执行
import java.lang.reflect.Method;
public class test {
public static void main(String[] args) throws Exception {
Object o = Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(null);
Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(o,"open /System/Applications/Calculator.app\n");
}
}
现在可以打开计算器,明白什么是序列与反序列化了。
看雪ID:p1yang
https://bbs.pediy.com/user-home-934060.htm
# 往期推荐
1.CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析
3.The House of Mind (FASTBIN METHOD) + PRIME
4.Android APP漏洞之战—插件化漏洞和解压缩漏洞详解
球分享
球点赞
球在看
点击“阅读原文”,了解更多!